
#ifndef SANITIZER_INTERNAL_DEFS_H
#define SANITIZER_INTERNAL_DEFS_H

#define SanitizerToolName "ASAN"
#define UINT64_MAX 0xffffffffffffffff
#define INT64_MAX  0x7fffffffffffffff
#define INT64_MIN  0x8000000000000000

#define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
#define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
#define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE

#define SANITIZER_INTERFACE_WEAK_DEF(ReturnType, Name, ...) \
  extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE ReturnType Name(__VA_ARGS__)

#define SANITIZER_WORDSIZE 64

namespace __sanitizer {

typedef unsigned long uptr;
typedef signed long sptr;

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long s64;

typedef int fd_t;
typedef int error_t;

typedef int pid_t;

typedef uptr OFF_T;
typedef u64 OFF64_T;

typedef u32 operator_new_size_type;

typedef u64 tid_t;

#define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
#define SANITIZER_WEAK_DEFAULT_IMPL extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
#define SANITIZER_WEAK_CXX_DEFAULT_IMPL extern "C++" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE

#define ALWAYS_INLINE inline __attribute__((always_inline))
#define ALIAS(x) __attribute__((alias(x)))
// Please only use the ALIGNED macro before the type.
// Using ALIGNED after the variable declaration is not portable!
#define ALIGNED(x) __attribute__((aligned(x)))
#define FORMAT(f, a) __attribute__((format(printf, f, a)))
#define NOINLINE __attribute__((noinline))
#define NORETURN __attribute__((noreturn))
#define THREADLOCAL __thread
#define LIKELY(x) __builtin_expect(!!(x), 1)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)

// Unaligned versions of basic types.
typedef ALIGNED(1) u16 uu16;
typedef ALIGNED(1) u32 uu32;
typedef ALIGNED(1) u64 uu64;
typedef ALIGNED(1) s16 us16;
typedef ALIGNED(1) s32 us32;
typedef ALIGNED(1) s64 us64;

#define GET_CALLER_PC() (__sanitizer::uptr) __builtin_return_address(0)
#define GET_CURRENT_FRAME() (__sanitizer::uptr) __builtin_frame_address(0)

// Forces the compiler to generate a frame pointer in the function.
#define ENABLE_FRAME_POINTER              \
  do {                                    \
    volatile __sanitizer::uptr enable_fp; \
    enable_fp = GET_CURRENT_FRAME();      \
    (void)enable_fp;                      \
  } while (0)

// NOTE: Functions below must be defined in each run-time.
void NORETURN Die();
void NORETURN CheckFailed(const char *file, int line, const char *cond,
                          u64 v1, u64 v2);

void Printf(const char *format, ...);
void RawWrite(const char* msg);

#define ASAN_LOG_DEBUG 4
#define ASAN_LOG_INFO  3
#define ASAN_LOG_WARN  2
#define ASAN_LOG_ERR   1
#define ASAN_LOG_NONE  0

inline int Verbosity() {return ASAN_LOG_ERR;}

// Check macro
#define RAW_CHECK_MSG(expr, msg, ...)          \
  do {                                         \
    if (UNLIKELY(!(expr))) {                   \
      const char* msgs[] = {msg, __VA_ARGS__}; \
      for (const char* m : msgs) RawWrite(m);  \
      Die();                                   \
    }                                          \
  } while (0)

#define RAW_CHECK(expr) RAW_CHECK_MSG(expr, #expr "\n", )
#define RAW_CHECK_VA(expr, ...) RAW_CHECK_MSG(expr, #expr "\n", __VA_ARGS__)

#define CHECK_IMPL(c1, op, c2) \
  do { \
    __sanitizer::u64 v1 = (__sanitizer::u64)(c1); \
    __sanitizer::u64 v2 = (__sanitizer::u64)(c2); \
    if (UNLIKELY(!(v1 op v2))) \
      __sanitizer::CheckFailed(__FILE__, __LINE__, \
        "(" #c1 ") " #op " (" #c2 ")", v1, v2); \
  } while (false) \
/**/

#define CHECK(a)       CHECK_IMPL((a), !=, 0)
#define CHECK_EQ(a, b) CHECK_IMPL((a), ==, (b))
#define CHECK_NE(a, b) CHECK_IMPL((a), !=, (b))
#define CHECK_LT(a, b) CHECK_IMPL((a), <,  (b))
#define CHECK_LE(a, b) CHECK_IMPL((a), <=, (b))
#define CHECK_GT(a, b) CHECK_IMPL((a), >,  (b))
#define CHECK_GE(a, b) CHECK_IMPL((a), >=, (b))

#define VReport(level, ...)                                              \
  do {                                                                   \
    if ((uptr)Verbosity() >= (level)) Printf(__VA_ARGS__); \
  } while (false)

#define ASSERT(c, msg) \
  do {                                                          \
    if (!c) {Printf((msg)); Die();}   \
  } while (false)

#define UNREACHABLE(msg) do { \
  ASSERT(0, msg); \
  Die(); \
} while (0)

// Internal thread identifier allocated by ThreadRegistry.
typedef u32 Tid;
constexpr Tid kInvalidTid = -1;
constexpr Tid kMainTid = 0;
typedef u32 Pid;

// Stack depot stack identifier.
typedef u32 StackID;
const StackID kInvalidStackID = 0;

extern bool asan_inited;
extern bool asan_init_is_running;
extern bool asan_interceptor_inited;

}  // namespace __sanitizer

#endif // SANITIZER_INTERNAL_DEFS_H